package com.jg.blog.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jg.blog.config.WeChatConfig;
import com.jg.blog.constant.RedisKeyConstant;
import com.jg.blog.enums.ResultEnum;
import com.jg.blog.enums.StateEnums;
import com.jg.blog.pojo.User;
import com.jg.blog.service.UserService;
import com.jg.blog.token.UserToken;
import com.jg.blog.utils.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 杨德石
 * @Date: 2020/2/9 20:45
 * @Version 1.0
 */
@RestController
@RequestMapping("/user")
@SuppressWarnings("all")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WeChatConfig weChatConfig;

    /**
     * 保存
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public Result<Object> save(@RequestBody User user) {
        userService.save(user);
        return new Result<>("添加成功！");
    }

    /**
     * 更新
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/update", method = RequestMethod.PUT)
    public Result<Object> update(@RequestBody User user) {
        userService.update(user);
        return new Result<>("修改成功！");
    }

    /**
     * 修改个人信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/updateInfo", method = RequestMethod.PUT)
    public Result<Object> updateInfo(@RequestBody User user) {
        userService.updateInfo(user);
        return new Result<>("修改成功！");
    }

    /**
     * 根据id查询
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
    public Result<User> get(@PathVariable Integer id) {
        User user = userService.getById(id);
        return new Result<>(user);
    }

    /**
     * 根据id删除
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    public Result<Object> delete(@PathVariable Integer id) {
        userService.deleteById(id);
        return new Result<>("删除成功！");
    }

    /**
     * 分页查询
     *
     * @param page
     * @return
     */
    @RequestMapping(value = "/getByPage", method = RequestMethod.POST)
    public Result<Page<User>> getByPage(@RequestBody Page<User> page) {
        String sortColumn = page.getSortColumn();
        if (StringUtils.isNotBlank(sortColumn)) {
            // 排序列不为空
            String[] sortColumns = {"sex", "created_time", "update_time"};
            List<String> sortList = Arrays.asList(sortColumns);
            if (!sortList.contains(sortColumn.toLowerCase())) {
                return new Result<>(ResultEnum.PARAMS_ERROR.getCode(), "排序参数不合法！");
            }
        }
        page = userService.getByPage(page);
        return new Result<>(page);
    }

    /**
     * 获取登录中的用户
     *
     * @return
     */
    @RequestMapping(value = "getLoginUser", method = RequestMethod.GET)
    public Result<Object> getUser() {
        User loginUser = (User) ShiroUtils.getLoginUser();
        return new Result<>(loginUser);
    }

    /**
     * 验证用户是否登录
     *
     * @return
     */
    @RequestMapping(value = "validateUser", method = RequestMethod.POST)
    public Result<Object> validateUser() {
        String validateLogin = "0";
        Map<String, Object> returnMap = new HashMap<>(2);
        User user = (User) ShiroUtils.getLoginUser();
        if (user != null) {
            // 登录中
            validateLogin = "1";
        }
        returnMap.put("validateLogin", validateLogin);
        return new Result<>(returnMap);
    }

    /**
     * 重置密码
     *
     * @return
     */
    @RequestMapping(value = "/resetPwd", method = RequestMethod.PUT)
    public Result<Object> resetPwd(@RequestBody List<Integer> userIds) {
        userService.resetPwd(userIds);
        return new Result<>("重置完毕！");
    }

    /**
     * 注册
     */
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    public Result<Object> register(@RequestBody User user) {
        userService.register(user);
        return new Result<>("注册成功！");
    }

    /**
     * H5登录
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<Object> login(@RequestBody User user) {
        if (user == null || StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) {
            return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误！");
        }
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UserToken(user.getUsername(), user.getPassword(), StateEnums.USER.getCode());
        try {
            subject.login(authenticationToken);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "用户名或密码错误！");
        }
        // 登录成功
        Serializable sessionId = subject.getSession().getId();
        User u = (User) subject.getPrincipal();
        u.setPassword("");
        u.setDeleted(null);
        // 存放redis
        redisTemplate.opsForValue().set(RedisKeyConstant.TOKEN_KEY + ":" + sessionId, subject.getPrincipal(), 60 * 60 * 12, TimeUnit.SECONDS);
        Map<String, Object> returnMap = new HashMap<>(2);
        returnMap.put("token", sessionId);
        returnMap.put("user", u);
        return new Result<>(returnMap);
    }



    /**
     * 查询当前用户的评论数和收藏数
     *
     * @return
     */
    @RequestMapping(value = "/commentAndCollectionCount", method = RequestMethod.GET)
    public Result<Map<String, Object>> commentAndCollectionCount() {
        Map<String, Object> countMap = userService.getCommentAndCollectionCount();
        return new Result<>(countMap);
    }

    /**
     * 获取openid
     *
     * @param code
     * @return
     */
    @RequestMapping(value = "/getOpenId/{code}", method = RequestMethod.GET)
    public Result<Object> getOpenId(@PathVariable String code) throws IOException {
        // 请求路径
        String url = weChatConfig.getWeixinAuthUrl() + code;
        String body = HttpUtils.get(url).body();
        JSONObject jsonObject = JSON.parseObject(body);
        return new Result<>("获取openid", jsonObject.getString("openid"));
    }

    /**
     * 完善信息
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/updateUsername", method = RequestMethod.PUT)
    public Result<Object> updateUsername(@RequestBody User user) {
        User u = (User) ShiroUtils.getLoginUser();
        u.setUsername(user.getUsername());
        u.setPassword(user.getPassword());
        userService.updateInfo(u);
        return new Result<>("设置成功！");
    }

    /**
     * 微信注册
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "registerWX", method = RequestMethod.POST)
    public Result<Object> registerWX(@RequestBody User user) throws IOException {
        // 获取code
        String code = user.getCode();
        String url = weChatConfig.getWeixinAuthUrl() + code;
        String body = HttpUtils.get(url).body();
        JSONObject jsonObject = JSON.parseObject(body);
        String openid = jsonObject.getString("openid");
        String validateLogin = "0";

        // openid查询
        User u = userService.getByOpenId(openid);
        if (u == null || u.getDeleted() == 1) {
            // 用户不存在或已被删除，先注册，，在登录
            user.setOpenId(openid);
            // 注册
            userService.registerWX(user);
            validateLogin = "1";
        }
        user.setOpenId(openid);
        // 登录
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UserToken(openid, openid, StateEnums.USER_WX.getCode());
        try {
            subject.login(authenticationToken);
        } catch (Exception e) {
            return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "登录失败！");
        }
        // 登录成功
        Serializable sessionId = subject.getSession().getId();
        u = (User) subject.getPrincipal();
        u.setPassword("");
        u.setDeleted(null);
        // 存放redis
        redisTemplate.opsForValue().set(RedisKeyConstant.TOKEN_KEY + ":" + sessionId, subject.getPrincipal(), 60 * 60 * 12, TimeUnit.SECONDS);
        Map<String, Object> returnMap = new HashMap<>(2);
        returnMap.put("token", sessionId);
        returnMap.put("user", u);
        returnMap.put("validateLogin", validateLogin);
        return new Result<>(returnMap);
    }


    /**
     * 微信登录
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "/wxLogin/{code}", method = RequestMethod.GET)
    public Result<Object> wxLogin(@PathVariable String code) throws IOException {
        // 获取code
        String url = weChatConfig.getWeixinAuthUrl() + code;
        String body = HttpUtils.get(url).body();
        JSONObject jsonObject = JSON.parseObject(body);
        String openid = jsonObject.getString("openid");
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UserToken(openid, openid, StateEnums.USER_WX.getCode());
        try {
            subject.login(authenticationToken);
        } catch (Exception e) {
            return new Result<>(ResultEnum.NOT_USER.getCode(), "用户名不存在！");
        }
        // 登录成功
        Serializable sessionId = subject.getSession().getId();
        User u = (User) subject.getPrincipal();
        u.setPassword("");
        u.setDeleted(null);
        // 存放redis
        redisTemplate.opsForValue().set(RedisKeyConstant.TOKEN_KEY + ":" + sessionId, subject.getPrincipal(), 60 * 60 * 12, TimeUnit.SECONDS);
        Map<String, Object> returnMap = new HashMap<>(2);
        returnMap.put("token", sessionId);
        returnMap.put("user", u);
        return new Result<>(returnMap);
    }

    /**
     * App微信登录
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "loginWXApp", method = RequestMethod.POST)
    public Result<Object> loginWXApp(@RequestBody User user) throws IOException {
        // 获取code
        String openid = user.getOpenId();
        if (StringUtils.isBlank(openid)) {
            return new Result<>(StateEnums.REQUEST_ERROR.getCode(), "微信授权失败，请使用账号密码登录！");
        }
        String validateLogin = "0";
        // openid查询
        User u = userService.getByOpenId(openid);
        if (u == null || u.getDeleted() == 1) {
            // 用户不存在或已被删除，先注册，，在登录
            user.setOpenId(openid);
            validateLogin = "1";
            // 注册
            userService.registerWX(user);
        }
        user.setOpenId(openid);

        // 登录
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken authenticationToken = new UserToken(openid, openid, StateEnums.USER_WX.getCode());
        try {
            subject.login(authenticationToken);
        } catch (Exception e) {
            return new Result<>(ResultEnum.PARAMS_NULL.getCode(), "登录失败！");
        }
        // 登录成功
        Serializable sessionId = subject.getSession().getId();
        u = (User) subject.getPrincipal();
        u.setPassword("");
        u.setDeleted(null);
        // 存放redis
        redisTemplate.opsForValue().set(RedisKeyConstant.TOKEN_KEY + ":" + sessionId, subject.getPrincipal(), 60 * 60 * 12, TimeUnit.SECONDS);
        Map<String, Object> returnMap = new HashMap<>(2);
        returnMap.put("token", sessionId);
        returnMap.put("user", u);
        returnMap.put("validateLogin", validateLogin);
        return new Result<>(returnMap);
    }


    @RequestMapping(value = "closeUser",method = RequestMethod.GET)
    public Result<Object> closeObject() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return new Result<>("退出登录成功！");
    }
}
